package com.eedi.framework.dept.service;

import cn.hutool.core.collection.CollUtil;
import com.google.common.annotations.VisibleForTesting;
import com.eedi.framework.common.enums.CommonStatusEnum;
import com.eedi.framework.common.pojo.PageResult;
import com.eedi.framework.common.util.object.BeanUtils;
import com.eedi.framework.datapermission.core.annotation.DataPermission;
import com.eedi.framework.dept.controller.org.vo.OrgDeptListReq;
import com.eedi.framework.dept.controller.org.vo.OrgDeptPageReq;
import com.eedi.framework.dept.controller.org.vo.OrgDeptSaveReq;
import com.eedi.framework.dept.controller.org.vo.OrgDeptUpReq;
import com.eedi.framework.dept.dal.OrgDeptCacheKeyConstants;
import com.eedi.framework.dept.dal.dataobject.OrgDeptDO;
import com.eedi.framework.dept.dal.mapper.OrgDeptMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;

import javax.annotation.Resource;
import java.util.*;

import static com.eedi.framework.common.exception.util.ServiceExceptionUtil.exception;
import static com.eedi.framework.common.util.collection.CollectionUtils.convertSet;
import static com.eedi.framework.dept.enmus.OrgDeptErrorCodeConstants.*;


/**
 * 部门 Service 实现类
 *
 */
@Service
@Validated
@Slf4j
public class OrgDeptServiceImpl implements OrgDeptService {

    @Resource
    private OrgDeptMapper orgDeptMapper;

    @Override
    @CacheEvict(cacheNames = OrgDeptCacheKeyConstants.ORG_DEPT_CHILDREN_ID_LIST,
            allEntries = true) // allEntries 清空所有缓存，因为操作一个部门，涉及到多个缓存
    public String createDept(OrgDeptSaveReq createReqVO) {
        if (createReqVO.getParentOrgDeptId() == null) {
            createReqVO.setParentOrgDeptId(OrgDeptDO.PARENT_ID_ROOT);
        }
        // 校验父部门的有效性
        validateParentDept(null, createReqVO.getParentOrgDeptId());
        // 校验部门名的唯一性
        validateDeptNameUnique(null, createReqVO.getParentOrgDeptId(), createReqVO.getOrgDeptName());

        // 插入部门
        OrgDeptDO dept = BeanUtils.toBean(createReqVO, OrgDeptDO.class);
        dept.setOrgDeptStatus(CommonStatusEnum.ENABLE);
        orgDeptMapper.insert(dept);
        return dept.getOrgDeptId();
    }

    @Override
    // allEntries 清空所有缓存，因为操作一个部门，涉及到多个缓存
    @CacheEvict(cacheNames = OrgDeptCacheKeyConstants.ORG_DEPT_CHILDREN_ID_LIST,
            allEntries = true)
    public void updateDept(OrgDeptUpReq updateReqVO) {
        if (updateReqVO.getParentOrgDeptId() == null) {
            updateReqVO.setParentOrgDeptId(OrgDeptDO.PARENT_ID_ROOT);
        }
        // 校验自己存在
        validateDeptExists(updateReqVO.getOrgDeptId());
        // 校验父部门的有效性
        validateParentDept(updateReqVO.getOrgDeptId(), updateReqVO.getParentOrgDeptId());
        // 校验部门名的唯一性
        validateDeptNameUnique(updateReqVO.getOrgDeptId(), updateReqVO.getParentOrgDeptId(), updateReqVO.getOrgDeptName());

        // 更新部门
        OrgDeptDO updateObj = BeanUtils.toBean(updateReqVO, OrgDeptDO.class);
        orgDeptMapper.updateById(updateObj);
    }

    @Override
    // allEntries 清空所有缓存，因为操作一个部门，涉及到多个缓存
    @CacheEvict(cacheNames = OrgDeptCacheKeyConstants.ORG_DEPT_CHILDREN_ID_LIST,
            allEntries = true)
    public void deleteDept(String deptId) {
        // 校验是否存在
        validateDeptExists(deptId);
        // 校验是否有子部门
        if (orgDeptMapper.selectCountByParentId(deptId) > 0) {
            throw exception(ORG_DEPT_EXITS_CHILDREN);
        }
        // 删除部门
        orgDeptMapper.deleteById(deptId);
    }

    @Override
    public void disable(String deptId) {
        // 校验自己存在
        validateDeptExists(deptId);
        orgDeptMapper.updateStatusByOrgDeptId(deptId, CommonStatusEnum.DISABLE);
    }

    @Override
    public void enable(String deptId) {
        // 校验自己存在
        validateDeptExists(deptId);
        orgDeptMapper.updateStatusByOrgDeptId(deptId, CommonStatusEnum.ENABLE);
    }

    @VisibleForTesting
    void validateDeptExists(String deptId) {
        if (deptId == null) {
            return;
        }
        OrgDeptDO dept = orgDeptMapper.selectById(deptId);
        if (dept == null) {
            throw exception(ORG_DEPT_NOT_FOUND);
        }
    }

    @VisibleForTesting
    void validateParentDept(String deptId, String parentDeptId) {
        if (parentDeptId == null || OrgDeptDO.PARENT_ID_ROOT.equals(parentDeptId)) {
            return;
        }
        // 1. 不能设置自己为父部门
        if (Objects.equals(deptId, parentDeptId)) {
            throw exception(ORG_DEPT_PARENT_ERROR);
        }
        // 2. 父部门不存在
        OrgDeptDO parentDept = orgDeptMapper.selectById(parentDeptId);
        if (parentDept == null) {
            throw exception(ORG_DEPT_PARENT_NOT_EXITS);
        }
        // 3. 递归校验父部门，如果父部门是自己的子部门，则报错，避免形成环路
        if (deptId == null) {
            // id 为空，说明新增，不需要考虑环路
            return;
        }
        for (int i = 0; i < Short.MAX_VALUE; i++) {
            // 3.1 校验环路
            parentDeptId = parentDept.getParentOrgDeptId();
            if (Objects.equals(deptId, parentDeptId)) {
                throw exception(ORG_DEPT_PARENT_IS_CHILD);
            }
            // 3.2 继续递归下一级父部门
            if (parentDeptId == null || OrgDeptDO.PARENT_ID_ROOT.equals(parentDeptId)) {
                break;
            }
            parentDept = orgDeptMapper.selectById(parentDeptId);
            if (parentDept == null) {
                break;
            }
        }
    }

    @VisibleForTesting
    void validateDeptNameUnique(String deptId, String parentDeptId, String name) {
        OrgDeptDO dept = orgDeptMapper.selectByParentIdAndName(parentDeptId, name);
        if (dept == null) {
            return;
        }
        // 如果 deptId 为空，说明不用比较是否为相同 deptId 的部门
        if (deptId == null) {
            throw exception(ORG_DEPT_NAME_DUPLICATE);
        }
        if (dept.getOrgDeptId().equals(deptId)) {
            throw exception(ORG_DEPT_NAME_DUPLICATE);
        }
    }

    @Override
    public OrgDeptDO getDept(String deptId) {
        return orgDeptMapper.selectById(deptId);
    }

    @Override
    public List<OrgDeptDO> getDeptList(Collection<String> deptIds) {
        if (CollUtil.isEmpty(deptIds)) {
            return Collections.emptyList();
        }
        return orgDeptMapper.selectBatchIds(deptIds);
    }

    @Override
    public List<OrgDeptDO> getDeptList(OrgDeptListReq reqVO) {
        List<OrgDeptDO> list = orgDeptMapper.selectList(reqVO);
        list.sort(Comparator.comparing(OrgDeptDO::getOrgDeptSort));
        return list;
    }

    @Override
    public List<OrgDeptDO> getChildDeptList(String deptId) {
        List<OrgDeptDO> children = new LinkedList<>();
        // 遍历每一层
        Collection<String> parentIds = Collections.singleton(deptId);
        for (int i = 0; i < Short.MAX_VALUE; i++) {
            // 使用 Short.MAX_VALUE 避免 bug 场景下，存在死循环
            // 查询当前层，所有的子部门
            List<OrgDeptDO> depts = orgDeptMapper.selectListByParentId(parentIds);
            // 1. 如果没有子部门，则结束遍历
            if (CollUtil.isEmpty(depts)) {
                break;
            }
            // 2. 如果有子部门，继续遍历
            children.addAll(depts);
            parentIds = convertSet(depts, OrgDeptDO::getOrgDeptId);
        }
        return children;
    }

    @Override
    @DataPermission(enable = false) // 禁用数据权限，避免建立不正确的缓存
    @Cacheable(cacheNames = OrgDeptCacheKeyConstants.ORG_DEPT_CHILDREN_ID_LIST, key = "#orgDeptId")
    public Set<String> getChildDeptIdListFromCache(String orgDeptId) {
        List<OrgDeptDO> children = getChildDeptList(orgDeptId);
        return convertSet(children, OrgDeptDO::getOrgDeptId);
    }

    @Override
    public void validateDeptList(Collection<String> deptIds) {
        if (CollUtil.isEmpty(deptIds)) {
            return;
        }
        // 获得科室信息
        Map<String, OrgDeptDO> deptMap = getDeptMap(deptIds);
        // 校验
        deptIds.forEach(deptId -> {
            OrgDeptDO dept = deptMap.get(deptId);
            if (dept == null) {
                throw exception(ORG_DEPT_NOT_FOUND);
            }
            if (!CommonStatusEnum.ENABLE.equals(dept.getOrgDeptStatus())) {
                throw exception(ORG_DEPT_NOT_ENABLE, dept.getOrgDeptName());
            }
        });
    }

    @Override
    public Long countOrgDept() {
        return this.orgDeptMapper.selectCount();
    }

    @Override
    public PageResult<OrgDeptDO> getDeptPage(OrgDeptPageReq reqVO) {

        return orgDeptMapper.selectDeptByPage(reqVO);
    }

    /**
     * 根据dept-name获取deptDO
     *
     * @param deptNames
     * @return
     */
    @Override
    public List<OrgDeptDO> listByDeptNames(Collection<String> deptNames) {
        return orgDeptMapper.listByDeptNames(deptNames);
    }

}
